package com.xcm.filter;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.xcm.cache.RedisCacheDao;
import com.xcm.config.CustomProperties;
import com.xcm.constant.SSOFilterConstant;
import com.xcm.util.DESUtils;
import com.xcm.util.RestClientUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录验证filter
 */
public class SSOLoginFilter implements Filter {
    private String cookieName;
    private String ssoServerUrl;
    private String platformTag;
    private String secretKey;
    private RedisCacheDao redisCacheDao;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ServletContext servletContext = filterConfig.getServletContext();
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        CustomProperties customProperties = (CustomProperties) webApplicationContext.getBean("customProperties");
        redisCacheDao = (RedisCacheDao) webApplicationContext.getBean("redisCacheDao");
        cookieName = customProperties.getCookieName();
        ssoServerUrl = customProperties.getSsoLoginUrl();
        platformTag = customProperties.getPlatformTag();
        secretKey = customProperties.getSecretKey();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //上下文路径
        String path = request.getContextPath();
        //gotoURL
        String gotoURL = request.getParameter(SSOFilterConstant.SSO_FILTER_GOTOURL);
        if (gotoURL == null) {
            gotoURL = request.getRequestURL().toString();
        }
        StringBuilder urlSb = new StringBuilder();
        //setCookieURL
        String setCookieURL = urlSb.append(request.getScheme()).append("://").append(request.getServerName())
                .append(":").append(request.getServerPort()).append(path).append("/setCookie").toString();
        //重置urlSb
        urlSb.setLength(0);
        urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
                .append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
        String url = urlSb.toString();

        Cookie ticket = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(cookieName)) {
                    ticket = cookie;
                    break;
                }
            }
        }
        String requestURI = request.getRequestURI();
        if (requestURI.equals(path + "/logout")) {
            doLogout(ticket, response);
            //注销成功，重定向到登录界面，登录成功，默认跳转到首页
            //重置urlSb
            urlSb.setLength(0);
            gotoURL = urlSb.append(request.getScheme()).append("://")
                    .append(request.getServerName()).append(":").append(request.getServerPort())
                    .append(path).append("/index").toString();
            //重置urlSb
            urlSb.setLength(0);
            urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
                    .append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
            response.sendRedirect(urlSb.toString());
            return;
        } else if (requestURI.equals(path + "/setCookie")) {
            setCookie(request, response);
        } else if (ticket != null) {
            authCookie(request, response, chain, ticket, setCookieURL, gotoURL);
        } else if (requestURI.equals(path + "/publish/update")) {
            //放开DSP请求接口(广告发布)
            chain.doFilter(request, response);
            return;
        } else if (requestURI.equals(path + "/file/upload/noLimit") || requestURI.equals(path + "/file/upload/noLimitWithCompress")) {
            //放开上传素材请求（无文件后缀限制）
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.addHeader("Access-Control-Allow-Credentials", "true");
            chain.doFilter(request, response);
            return;
        } else {
            response.sendRedirect(url);
        }
        return;
    }

    /**
     * 验证Cookie
     */
    private void authCookie(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Cookie ticket, String setCookieURL, String gotoURL) throws ServletException, IOException {
        String ticketValue = ticket.getValue();
        StringBuilder urlSb = new StringBuilder(ssoServerUrl).append("authTicket");
        Object obj = redisCacheDao.getCache("SSOTickets", DESUtils.decrypt(ticketValue, secretKey));
        if (obj == null) {
            //验证失败，返回登录界面
            urlSb.setLength(0);
            urlSb.append(ssoServerUrl).append("preLogin?setCookieURL=").append(DESUtils.encrypt(setCookieURL, secretKey))
                    .append("&gotoURL=").append(DESUtils.encrypt(gotoURL, secretKey)).append("&platformTag=").append(platformTag);
            response.sendRedirect(urlSb.toString());
            return;
        } else {
            //把cookie放入request中，需要获取用户信息，从request取出cookie值，去redis从获取用户的信息
            request.setAttribute(cookieName, ticketValue);
            chain.doFilter(request, response);
            return;
        }
    }

    /**
     * 设置Cookie
     */
    private void setCookie(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Cookie ticket = new Cookie(cookieName, request.getParameter(SSOFilterConstant.SSO_FILTER_TICKET));
        ticket.setPath("/");
        ticket.setMaxAge(Integer.parseInt(request.getParameter(SSOFilterConstant.SSO_FILTER_EXPIRY)));
        response.addCookie(ticket);

        String gotoURL = request.getParameter(SSOFilterConstant.SSO_FILTER_GOTOURL);
        if (gotoURL != null) {
            response.sendRedirect(DESUtils.decrypt(gotoURL, secretKey));
        }
    }

    /**
     * 注销
     */
    private void doLogout(Cookie ticket, HttpServletResponse response) throws IOException {
        Map<String, Object> params = new HashMap<>();
        params.put(SSOFilterConstant.SSO_FILTER_TICKET, ticket.getValue());

        StringBuilder urlSb = new StringBuilder();
        String url = urlSb.append(ssoServerUrl).append("logout").toString();
        try {
            JSONObject result = post(url, params);
            int code = result.getIntValue("code");
            //注销成功，删除cookie
            if (SSOFilterConstant.CODE_SUCCESS == code) {
                ticket.setValue(null);
                ticket.setMaxAge(0);
                ticket.setPath("/");
                response.addCookie(ticket);
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private JSONObject post(String url, Map<String, Object> params) throws JSONException {
        String post = RestClientUtils.post(url, params, "UTF-8");
        return JSON.parseObject(post);
    }

    @Override
    public void destroy() {

    }
}
